package com.deuwise.system.controller;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.deuwise.common.utils.SpringContextHolder;
import com.deuwise.common.validator.ValidatorUtils;
import com.deuwise.common.validator.group.AddGroup;
import com.deuwise.system.entity.LayerTypeDo;
import com.deuwise.system.entity.SysLayerSyncHist;
import com.deuwise.system.service.LayerTypeDoService;
import com.deuwise.system.service.SysLayerSyncHistService;
import com.deuwise.system.service.SysMapViewsDictService;
import io.swagger.annotations.*;
import io.swagger.annotations.ApiImplicitParams;
import com.deuwise.common.utils.R;
import com.deuwise.common.utils.Result;
import com.baomidou.mybatisplus.plugins.Page;
import com.deuwise.system.entity.SysLayerDict;
import com.deuwise.system.service.SysLayerDictService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

/**
 *@author deuwise
 *@date 2020-05-15 09:51:27
 */
@Api(tags = "图层字典模块", description = "图层字典信息")
@RequestMapping("api/sysLayerDict")
@RestController()
public class SysLayerDictController extends AbstractController{
    @Autowired
    private SysLayerDictService sysLayerDictService;
    /**图层类型*/
    @Autowired
    private LayerTypeDoService layerTypeDoService;
    /*api同步历史*/
    @Autowired
    private SysLayerSyncHistService sysLayerSyncHistService;

    @Autowired
    private SysMapViewsDictService sysMapViewsDictService;

    @ApiOperation(value = "获取信息", notes = "")
    @RequestMapping(value = "/select", method = RequestMethod.GET)
    public R select(){
        Page<SysLayerDict> syslayerdictPage = sysLayerDictService.selectPage(new Page<SysLayerDict>());
        return R.ok(syslayerdictPage);
    }

    @ApiOperation(value = "获取list", notes = "")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @ApiImplicitParams({
            @ApiImplicitParam(name="version",value = "api版本号",dataType = "String", paramType = "query", required = true),
            @ApiImplicitParam(name = "layerName", value = "图层名称",  dataType = "string", paramType = "query", required = true),
            @ApiImplicitParam(name = "layerType", value = "图层类型",  dataType = "string", paramType = "query", required = true),
            @ApiImplicitParam(name = "currentPage", value = "开始页数", defaultValue = "1", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "每页多少条", defaultValue = "15", dataType = "int", paramType = "query")})
    public Result<Page<SysLayerDict>> list(String layerName,String version, String layerType){
        Wrapper<SysLayerDict> wrapper = new EntityWrapper<SysLayerDict>();
        if (StringUtils.isNotBlank(layerName)) {
            wrapper.eq("layer_name", layerName);
        }
        if (StringUtils.isNotBlank(version)) {
            wrapper.eq("version", version);
        }
        if (StringUtils.isNotBlank(layerType)) {
            wrapper.eq("layer_type", layerType);
        }
        wrapper.orderBy("layer_name", false);
        Page<SysLayerDict> listPage = sysLayerDictService.selectPage(getPage(SysLayerDict.class),wrapper);
        return Result.ok(listPage);
     }

    @ApiOperation(value = "新增数据")
    @RequestMapping(value = "/insertSyslayerdict", method = RequestMethod.POST)
    public R insertSyslayerdict(@RequestBody SysLayerDict syslayerdict){
        boolean isSuccess = false;
        if(null == syslayerdict){
            return R.error(200,"新增数据失败，请稍后再试!");
        }

        ValidatorUtils.validateEntity(syslayerdict, AddGroup.class);
        Wrapper<SysLayerDict> wrapper = new EntityWrapper<SysLayerDict>();
        wrapper.eq("field", syslayerdict.getField());
        wrapper.eq("LAYER_NAME", syslayerdict.getLayerName());
        wrapper.eq("version",syslayerdict.getVersion());
        Integer count = sysLayerDictService.selectCount(wrapper);
        if (count > 0) {
            return R.error(500, "字段已经存在");
        }
        isSuccess = sysLayerDictService.insert(syslayerdict);
        if (isSuccess) {
            return R.ok();
        } else {
            return R.error(200, "新增数据失败，请稍后再试!");
        }
    }

    @ApiOperation(value = "编辑数据")
    @RequestMapping(value = "/updateSyslayerdict", method = RequestMethod.POST)
    public R updateSyslayerdict(@RequestBody SysLayerDict syslayerdict){
        boolean isSuccess = false;
        if(null == syslayerdict){
            return R.error(200,"数据编辑失败，请稍后再试!");
        }
        ValidatorUtils.validateEntity(syslayerdict, AddGroup.class);
        Wrapper<SysLayerDict> wrapper = new EntityWrapper<SysLayerDict>();
        wrapper.eq("field", syslayerdict.getField());
        wrapper.eq("LAYER_NAME", syslayerdict.getLayerName());
        wrapper.eq("version",syslayerdict.getVersion());
        wrapper.eq("id",syslayerdict.getId());
        Integer count = sysLayerDictService.selectCount(wrapper);
        if (count > 0) {
            return R.error(500, "字段已经存在");
        }
        isSuccess = sysLayerDictService.updateById(syslayerdict);
        if (isSuccess) {
            return R.ok();
        } else {
            return R.error(200,"数据编辑失败，请稍后再试!");
        }
    }

    @ApiOperation("删除字典")
    @DeleteMapping("/{id}")
    public R delete(@PathVariable("id") String id){

        sysLayerDictService.deleteById(id);

        return R.ok();
    }

    @ApiOperation(value = "批量删除记录")
    @RequestMapping(value = "/deleteSelect", method = RequestMethod.POST)
    public  R deleteSelect(@ApiParam(value = "ids集合",name = "ids",required = true) @RequestParam String[] ids){
        try {
            if (ids != null && ids.length > 0) {
                sysLayerDictService.deleteBatchIds(Arrays.asList(ids));
            }
        }catch (Exception ex){
            return  R.error("删除失败");
        }
        return  R.ok();
    }

    @ApiOperation(value = "已经更新图层版本号列表")
    @GetMapping("/layerVersionList")
    public R layerVersionList(){
        List<String> list = sysLayerDictService.layerVersionList();
        return R.ok(list);
    }

    @ApiOperation(value = "获取图层类型")
    @GetMapping("/LayerType")
    public R LayerType() {
        Map<String, String> list = new HashMap<>(16);
        Wrapper<LayerTypeDo> wrapper = new EntityWrapper<>();
        wrapper.orderBy("sort",true);
        List<LayerTypeDo> typeDoList= layerTypeDoService.selectList(wrapper);
        if (typeDoList != null && typeDoList.size()>0) {
            for (LayerTypeDo val : typeDoList) {
                list.put(val.getName(), val.getValue());
            }
        }
        return R.ok(list);
    }

    @ApiOperation(value = "图层字典不同版本比对")
    @RequestMapping(value = "/layerDictComparison", method = RequestMethod.GET)
    @ApiImplicitParams({
            @ApiImplicitParam(name="version1",value = "版本号1",dataType = "String", paramType = "query", required = true),
            @ApiImplicitParam(name="version2",value = "版本号2",dataType = "String", paramType = "query", required = true),
            @ApiImplicitParam(name = "layerType", value = "图层类型",  dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "viewType", value = "视图类型",  dataType = "string", paramType = "query")
    })
    public R layerDictComparison(String version1, String version2, String layerType, String viewType){
        if (StringUtils.isBlank(version1) || StringUtils.isBlank(version2)) {
            return R.error(200,"请选择任意两个版本进行比对");
        }
        // 是否返回所有字段
        boolean isFiledAll = false;
        Map<String, Map<String, String>> resMap = new LinkedHashMap<>(16);
        if (StringUtils.isBlank(layerType) && StringUtils.isBlank(viewType)) {
            // 图层为空，比对所有图层
            Wrapper<LayerTypeDo> wrapper = new EntityWrapper<LayerTypeDo>();
            List<LayerTypeDo> typeList = layerTypeDoService.selectList(wrapper);
            // 逐个图层比对
            for(LayerTypeDo typeDo : typeList){
                Map<String,String> map = dictComparisonBylayerType(typeDo.getValue(), version1, version2, isFiledAll);
                if(1 < map.size()){
                    resMap.put(typeDo.getName(), map);
                }
            }
            // 逐个视图比对
            List<String> list = sysMapViewsDictService.viewTypeVersionList();
            for(String type : list){
                Map<String,String> map = dictComparisonByViewType(type, version1, version2, isFiledAll);
                if(1 < map.size()) {
                    resMap.put(type, map);
                }
            }
        }else if(StringUtils.isNotBlank(layerType)){
            // 按单个图层比对
            isFiledAll = true;
            Map<String,String> map = dictComparisonBylayerType(layerType, version1, version2, isFiledAll);
            resMap.put(layerType, map);
        }else if(StringUtils.isNotBlank(viewType)){
            // 按单个视图比对
            isFiledAll = true;
            Map<String,String> map = dictComparisonByViewType(viewType, version1, version2, isFiledAll);
            resMap.put(viewType, map);
        }
        return R.ok(resMap);
    }

    /**
     * 按图层比对
     * @param layerType 图层类型
     * @param version1 版本号1
     * @param version2 版本号2
     * @return
     */
    public Map<String,String> dictComparisonBylayerType(String layerType, String version1, String version2, boolean isFiledAll){
        // 版本号1
        Map<String, String> param = new HashMap<>(16);
        param.put("version", version1);
        param.put("layerType", layerType);
        List<String> list1 = sysLayerDictService.layerFieldList(param);

        param.put("version", version2);
        List<String> list2 = sysLayerDictService.layerFieldList(param);

        Map<String,String> map = new LinkedHashMap<>(16);
        map.put(version1, version2);
        for(String field : list1){
            /*判断是否存在*/
            boolean flge = list2.stream().anyMatch(f -> field.trim().equals(f.trim()));
            if(flge){
                // 过滤掉相同字段
                if(isFiledAll){
                    map.put(field, field);
                }
                if(0 < list2.size()){
                    list2.remove(field);
                }
            }else{
                /*不存在，版本1多出的字段*/
                map.put(field, "add_field");
            }
        }

        for(int i = 0;i< list2.size();i++){
            /*版本1多出的字段*/
            map.put("add_field_" + i, list2.get(i));
        }
        return map;
    }

    /**
     * 按视图比对
     * @param viewType 视图类型
     * @param version1 版本号1
     * @param version2 版本号2
     * @return
     */
    public Map<String,String> dictComparisonByViewType(String viewType, String version1, String version2, boolean isFiledAll){
        // 版本号1
        Map<String, String> param = new HashMap<>(16);
        param.put("version", version1);
        param.put("viewType", viewType);
        List<String> list1 = sysMapViewsDictService.viewFieldList(param);

        param.put("version", version2);
        List<String> list2 = sysMapViewsDictService.viewFieldList(param);

        Map<String,String> map = new LinkedHashMap<>(16);
        map.put(version1, version2);
        for(String field : list1){
            /*判断是否存在*/
            boolean flge = list2.stream().anyMatch(f -> field.trim().equals(f.trim()));
            if(flge){
                // 过滤掉相同字段
                if(isFiledAll){
                    map.put(field, field);
                }
                if(0 < list2.size()){
                    list2.remove(field);
                }
            }else{
                /*不存在，版本1多出的字段*/
                map.put(field, "add_field");
            }
        }

        for(int i = 0;i< list2.size();i++){
            /*版本1多出的字段*/
            map.put("add_field_" + i, list2.get(i));
        }
        return map;
    }

    @ApiOperation(value = "全部图层属性同步")
    @GetMapping("/syncLayerProperty")
    public R syncLayerProperty(String apiUrl){
        if (StringUtils.isBlank(apiUrl)) {
            System.out.println("API地址不能为空！");
            return R.error(200,"ArcGis API地址不正确");
        }
        return getLayerList(apiUrl);
    }

    /**
     * 获取图层列表
     * @param url
     * @return
     */
    public R getLayerList(String url){
        StringBuffer urlSB = new StringBuffer();
        urlSB.append(url);
        urlSB.append("/latest/api-reference/");
        String[] resultArr = null;
        /*创建输入流用于读取流*/
        InputStream is=null;
        /*包装流,加快读取速度*/
        BufferedReader br=null;
        /*用来保存读取页面的数据.*/
        StringBuffer html=new StringBuffer();
        /*创建临时字符串用于保存每一次读的一行数据，然后html调用append方法写入temp;*/
        String  temp="";
        String version = "";
        try {
            /*获取URL;*/
            URL url2 = new URL(urlSB.toString());
            /*打开流，准备开始读取数据;*/
            is = url2.openStream();
            /*将流包装成字符流，调用br.readLine()可以提高读取效率，每次读取一行;*/
            br= new BufferedReader(new InputStreamReader(is));
            /*读取数据,调用br.readLine()方法每次读取一行数据,并赋值给temp,如果没数据则值==null,跳出循环;*/
            while ((temp = br.readLine()) != null) {
                /*将temp的值追加给html,这里注意的时String跟StringBuffere的区别前者不是可变的后者是可变的;*/
                html.append(temp);
            }
            /*接下来是关闭流,防止资源的浪费;*/
            if(is!=null)
            {
                is.close();
                is=null;
            }
            /*通过Jsoup解析页面,生成一个document对象;*/
            Document doc = Jsoup.parse(html.toString());
            /*通过class的名字得到（前端选择器，不是类！）*/
            Elements elements = doc.getElementsByClass("tab-section is-active leader-1 js-tab-section");
            Iterator<Element> iterator = elements.iterator();
            while(iterator.hasNext()){
                elements = iterator.next().getElementsByTag("ul");
                Element elm = elements.get(1);
                resultArr = elm.getElementsByTag("a").text().split(" ");
            }
            /*API版本号获取*/
            version = doc.getElementsByClass("secondary-nav-title tablet-hide").get(0).getElementsByTag("a").text();
            version = version.split(" ")[2];
            System.out.println("==========图层列表解析结束===========");
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return R.error(200,"ArcGis API地址不正确！");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return R.error(200,"ArcGis API地址不正确！");
        }
        List<String> success = new ArrayList<String>();
        List<String> fail = new ArrayList<String>();
        for (String layer : resultArr) {
            /*图层属性获取更新*/
            R r = syncLayerProperty(url, layer,version);
            if (0 == (int)r.get("code")) {
                success.add(layer);
            }else {
                fail.add(layer);
            }
        }
        Map<String,List<String>> resultMap = new HashMap<>(16);
        resultMap.put("更新成功图层", success);
        resultMap.put("更新失败图层", fail);
        /*插入同步历史记录*/
        SysLayerSyncHist syslayersynchist = new SysLayerSyncHist();
        syslayersynchist.setServerApi(url);
        syslayersynchist.setVersion(version);
        syslayersynchist.setSyncTime(new Date());
        syslayersynchist.setSyncInfo("更新成功图层:" + success.toString() +"," + "更新失败图层:" +fail.toString());
        insertSysLayerSyncHist(syslayersynchist);

        // 视图属性同步
        SysMapViewsDictController sysViewsDictController = SpringContextHolder.getBean(SysMapViewsDictController.class);
        R viewRes = sysViewsDictController.getViewsList(url);
        if("0".equals(viewRes.get("code"))){
            // 合并视图同步结果
            Map<String,List<String>> viewMap = new HashMap<>(16);
            viewMap = (Map<String,List<String>>)viewRes.get("data");
            resultMap.get("更新成功图层").addAll(viewMap.get("更新成功视图"));
            resultMap.get("更新失败图层").addAll(viewMap.get("更新失败视图"));
        }
        return R.ok(resultMap);
    }

    /**
     * 根据图层版本号同步更新图层属性
     * @param url
     * @param layerName
     * @return
     */
    public R syncLayerProperty(String url,String layerName,String version) {
        boolean flag = false;
        StringBuffer urlSb=new StringBuffer();
        if (StringUtils.isBlank(layerName)) {
            return R.error(200,"");
        }
        urlSb.append(url);
        urlSb.append("/latest/api-reference/esri-layers-");
        urlSb.append(layerName);
        urlSb.append(".html");

        InputStream is=null;
        BufferedReader br=null;
        StringBuffer html=new StringBuffer();
        String  temp="";
        try {
            URL url2 = new URL(urlSb.toString());
            /*打开流，准备开始读取数据;*/
            is = url2.openStream();
            br= new BufferedReader(new InputStreamReader(is));
            while ((temp = br.readLine()) != null) {
                html.append(temp);
            }
            /*接下来是关闭流,防止资源的浪费;*/
            if(is!=null)
            {
                is.close();
                is=null;
            }
            List<SysLayerDict> addList = new ArrayList<>();
            String layerType = "";
            /*通过Jsoup解析页面,生成一个document对象;*/
            Document doc = Jsoup.parse(html.toString());
            /*通过class的名字得到（前端选择器，不是类！）*/
            Elements elements = doc.getElementsByClass("table table-properties");
            Iterator<Element> iterator = elements.iterator();
            while(iterator.hasNext()){
                Element elemen = iterator.next();
                // 遍历属性列表行 tr
                Elements elementTr =  elemen.getElementsByTag("tr");
                // 去掉表头，所以下标从1开始
                for(int i = 1; i < elementTr.size(); i++){
                    Elements elementTd = elementTr.get(i).getElementsByTag("td");
                    if(0 < elementTd.size()){
                        // 遍历属性列表行 tr中的列 td,get(0) 表示第一列为 属性
                        Element element =  elementTd.get(0);
                        if(null != element){
                            // 属性字段获取
                            String field = element.getElementsByTag("a").text();
                            // field 为 type 的时候，要获取该图层的图层类型
                            if("type".equals(field)){
                                /*获取对应的图层类型*/
                                Elements typeElements = null;
                                Element elementType = elementTd.get(2);
                                typeElements = elementType.getElementsByClass("type-signature type-name");
                                if(0 < typeElements.size()){
                                    layerType = typeElements.get(0).getElementsByTag("a").text();
                                    if(StringUtils.isBlank(layerType)){
                                        layerType = typeElements.get(0).getElementsByClass("type-signature type-name").text();
                                    }
                                }else{
                                    // 第二种情况
                                    typeElements = elementType.getElementsByTag("code");
                                    if(0 < typeElements.size()){
                                        layerType = typeElements.get(0).text();
                                    }else{
                                        // 第三种情况，针对4.13版本某些图层
                                        layerType = elementType.getElementsByTag("a").get(1).text();
                                    }
                                }

                                layerType = layerType.replaceAll("\"","");
                            }

                            // 验证属性是否只读
                            boolean isflg = false;
                            if(!"type".equals(field)){
                                isflg = propertyVerification(doc, field);
                            }
                            if(!isflg){
                                /*构造对象*/
                                SysLayerDict sysLayerDict = new SysLayerDict();
                                sysLayerDict.setLayerName(layerName);
                                sysLayerDict.setVersion(version);
                                sysLayerDict.setField(field);
                                addList.add(sysLayerDict);
                            }
                        }
                    }
                }
                // 追加图层类型字段
                for(SysLayerDict sysLayerDict : addList){
                    sysLayerDict.setLayerType(layerType);
                }
            }
            /*移除当前版本图层对应属性*/
            if(deleteSysLayerDictByV(version,layerName)) {
                /*执行入库操作*/
                flag = sysLayerDictService.insertBatch(addList);
            }
            /*更新图层类型表*/
            insertLayerType(layerName,layerType);
            System.out.println(layerName + ":==========图层属性解析完成===========");
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return R.error(200,"ArcGis API地址不正确！");
        } catch (IOException e) {
            e.printStackTrace();
            return R.error(200,"图层属性同步异常，请稍后再试！");
        }

        return flag == true ? R.ok() : R.error();
    }

    /**
     * 判断属性字段是否为只读
     * @param doc
     * @param propertyName 属性名称(字段)
     * @return
     */
    public boolean propertyVerification(Document doc, String propertyName){
        Element element = doc.getElementById(propertyName);
        Elements elements = element.getElementsByClass("type-signature");
        for(Element element1 : elements){
            // 签名类型
            String typeSignature = element1.text();
            if("readonly".equals(typeSignature)){
                return true;
            }
        }
        return false;
    }

    /**
     * 移除指定版本号的图层属性
     * @param version 版本号
     * @param layerName 图层名称（图层类型）
     * @return
     */
    public boolean deleteSysLayerDictByV(String version, String layerName) {
        Wrapper<SysLayerDict> wrapper = new EntityWrapper<SysLayerDict>();
        if (StringUtils.isNotBlank(version)) {
            wrapper.eq("version", version);
        }
        if (StringUtils.isNotBlank(layerName)) {
            wrapper.eq("layer_name", layerName);
        }
        return sysLayerDictService.delete(wrapper);
    }

    /**
     * 将图层-类型加入记录表
     * @param layerName 图层名称
     * @param layerType 图层类型
     */
    public void insertLayerType(String layerName,String layerType){
        Wrapper<LayerTypeDo> wrapper = new EntityWrapper<>();
        if (StringUtils.isNotBlank(layerName)) {
            wrapper.eq("name", layerName);
        }
        int count = layerTypeDoService.selectCount(wrapper);
        if(0 == count){
            LayerTypeDo layerTypeDo = new LayerTypeDo();
            layerTypeDo.setName(layerName);
            layerTypeDo.setValue(layerType);
            layerTypeDoService.insert(layerTypeDo);
        }
    }

    /**
     * 新增历史记录
     * @param syslayersynchist
     */
    public void insertSysLayerSyncHist(SysLayerSyncHist syslayersynchist){
        if(null != syslayersynchist){
            if(StringUtils.isNotBlank(syslayersynchist.getVersion())){
                Wrapper<SysLayerSyncHist> wrapper = new EntityWrapper<SysLayerSyncHist>();
                wrapper.eq("version", syslayersynchist.getVersion());
                sysLayerSyncHistService.delete(wrapper);
            }
            // 删除已存在的版本，保留最新一次同步记录
            sysLayerSyncHistService.insert(syslayersynchist);
        }

    }
}